﻿using Microsoft.AspNetCore.DataProtection;

namespace Devonline.Identity;

/// <summary>
/// 基础加解密功能, 使用 类型 和 identity 编号进行加解密
/// </summary>
public static class DataProtectionExtensions
{
    /// <summary>
    /// 使用当前类型获取身份相关的 protector
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="provider"></param>
    /// <returns></returns>
    public static IDataProtector GetProtector<T>(this IDataProtectionProvider provider) where T : class => provider.CreateProtector(typeof(T).FullName);
    /// <summary>
    /// 使用字符串类型作为默认主键的方式获取身份相关的 protector
    /// </summary>
    /// <typeparam name="TIdentity"></typeparam>
    /// <param name="provider"></param>
    /// <param name="identity"></param>
    /// <returns></returns>
    public static IDataProtector GetProtector<TIdentity>(this IDataProtectionProvider provider, TIdentity identity) where TIdentity : IIdentity<string> => provider.CreateProtector(identity.Id);
    /// <summary>
    /// 使用泛型 TKey 类型作为默认主键的方式获取身份相关的 protector
    /// </summary>
    /// <typeparam name="TIdentity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="provider"></param>
    /// <param name="identity"></param>
    /// <returns></returns>
    public static IDataProtector GetProtector<TIdentity, TKey>(this IDataProtectionProvider provider, TIdentity identity) where TIdentity : IIdentity<TKey> => provider.CreateProtector(identity.Id.ToString());

    /// <summary>
    /// 使用当前类型 T 直接加密数据明文, 返回密文
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="provider"></param>
    /// <param name="plaintext"></param>
    /// <returns></returns>
    public static string Encrypt<T>(this IDataProtectionProvider provider, string plaintext) where T : class => provider.GetProtector<T>().Protect(plaintext);
    /// <summary>
    /// 使用当前类型 T 直接解密密文, 返回明文
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="provider"></param>
    /// <param name="ciphertext"></param>
    /// <returns></returns>
    public static string Decrypt<T>(this IDataProtectionProvider provider, string ciphertext) where T : class => provider.GetProtector<T>().Unprotect(ciphertext);

    /// <summary>
    /// 使用字符串类型作为默认主键的方式获取身份相关的 protector 直接加密数据明文, 返回密文
    /// </summary>
    /// <typeparam name="TIdentity"></typeparam>
    /// <param name="provider"></param>
    /// <param name="plaintext"></param>
    /// <returns></returns>
    public static string Encrypt<TIdentity>(this IDataProtectionProvider provider, TIdentity identity, string plaintext) where TIdentity : IIdentity<string> => provider.GetProtector(identity).Protect(plaintext);
    /// <summary>
    /// 使用字符串类型作为默认主键的方式获取身份相关的 protector 直接解密密文, 返回明文
    /// </summary>
    /// <typeparam name="TIdentity"></typeparam>
    /// <param name="provider"></param>
    /// <param name="ciphertext"></param>
    /// <returns></returns>
    public static string Decrypt<TIdentity>(this IDataProtectionProvider provider, TIdentity identity, string ciphertext) where TIdentity : IIdentity<string> => provider.GetProtector(identity).Unprotect(ciphertext);

    /// <summary>
    /// 使用泛型 TKey 类型作为默认主键的方式获取身份相关的 protector 直接加密数据明文, 返回密文
    /// </summary>
    /// <typeparam name="TIdentity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="provider"></param>
    /// <param name="plaintext"></param>
    /// <returns></returns>
    public static string Encrypt<TIdentity, TKey>(this IDataProtectionProvider provider, TIdentity identity, string plaintext) where TIdentity : IIdentity<TKey> => provider.GetProtector<TIdentity, TKey>(identity).Protect(plaintext);
    /// <summary>
    /// 使用泛型 TKey 类型作为默认主键的方式获取身份相关的 protector 直接解密密文, 返回明文
    /// </summary>
    /// <typeparam name="TIdentity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="provider"></param>
    /// <param name="ciphertext"></param>
    /// <returns></returns>
    public static string Decrypt<TIdentity, TKey>(this IDataProtectionProvider provider, TIdentity identity, string ciphertext) where TIdentity : IIdentity<TKey> => provider.GetProtector<TIdentity, TKey>(identity).Unprotect(ciphertext);
}